/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

#include "StdAfx.h"
#include ".\listofaddresses.h"
#include "ScanMessages.h"

#include <Winsock2.h>

#include <algorithm>

//---------------------------------------------------------------------------

ListOfAddresses::ListOfAddresses(void)
{
}

ListOfAddresses::~ListOfAddresses(void)
{
	CleanUp();
}

//---------------------------------------------------------------------------

void ListOfAddresses::CleanUp(void)
{
	MFullAddress *addr;

	for(iter=theVector.begin(); iter!=theVector.end(); iter++){
		addr = *iter;
		if(addr!=NULL){
			*iter = NULL;
			delete addr;
		}
	}
	theVector.clear();
}

//---------------------------------------------------------------------------

int ListOfAddresses::AddFullAddress(MFullAddress* addrIn)
{
	MFullAddress* addr;
	int cnt;

	if(addrIn==NULL) return MSR_ERR_OK;	// nothing to add

	addr = CreateAddress();
	if(addr==NULL) return MSR_ERR_MEMORY_ALLOC_ERROR;

	addr->LoadFromPointer(addrIn);

	cnt = (int)theVector.size();
	theVector.push_back(addr);
//	theVector.insert(theVector.begin(), addr);
	cnt = (int)theVector.size() - cnt;
	if(cnt!=1){
		delete addr;
		return MSR_ERR_MEMORY_ALLOC_ERROR;
	}

	return MSR_ERR_OK;
}

//---------------------------------------------------------------------------

MFullAddress* ListOfAddresses::CreateAddress(void)
{
	MFullAddress *addr;

	try{
		addr = new MFullAddress;
	}
	catch(...){
		addr = NULL;
	}
	return addr;
}

bool ListOfAddresses::AddAddress(int b1, int b2, int b3, int b4)
{
	MFullAddress *addr;
	int cnt;

	addr = CreateAddress();
	if(addr==NULL) return false;

	addr->addrIP.Set((BYTE)b1, (BYTE)b2, (BYTE)b3, (BYTE)b4);

	cnt = (int)theVector.size();
	theVector.push_back(addr);
	cnt = (int)theVector.size() - cnt;
	if(cnt!=1){
		delete addr;
		return false;
	}

	return true;
}

bool ListOfAddresses::BuildRange(CString strIn, int* range)
{
	CString v1, v2;
	int pos;
	int bbb;

	if(range==NULL) return false;

	if(strIn.CompareNoCase("*")==0){
		range[0] = 0;
		range[1] = 255;
		return true;
	}

	pos=strIn.Find('-', 0);
	if(pos!=-1){
		v1 = strIn.Left(pos);
		v2 = strIn.Mid(pos+1);
	}
	else{
		v1 = strIn;
		v2 = strIn;
	}

	try{
		range[0] = _tstoi(v1);
		range[1] = _tstoi(v2);
	}
	catch(...){
		return false;
	}

	if(range[0]<0 || range[0]>255) return false;
	if(range[1]<0 || range[1]>255) return false;

	if(range[0]>range[1]){
		bbb      = range[0];
		range[0] = range[1];
		range[1] = bbb;
	}

	return true;
}

bool ListOfAddresses::BuildAddressRange(CString strIn, int* range)
{
	CString str, r1, r2, r3, r4;
	int pos;

	str = strIn;

	pos = str.Find('.', 0);
	if(pos==-1) return false;
	r1  = str.Left(pos);
	str = str.Mid(pos+1);

	pos = str.Find('.', 0);
	if(pos==-1) return false;
	r2  = str.Left(pos);
	str = str.Mid(pos+1);

	pos = str.Find('.', 0);
	if(pos==-1) return false;
	r3  = str.Left(pos);
	r4  = str.Mid(pos+1);

	if(!BuildRange(r1, &range[0])) return false;
	if(!BuildRange(r2, &range[2])) return false;
	if(!BuildRange(r3, &range[4])) return false;
	if(!BuildRange(r4, &range[6])) return false;

	return true;
}

bool ListOfAddresses::AddAddressFromString(CString strIn)
{
	int range[8];
	int i1, i2, i3, i4;

	if(strIn.IsEmpty()) return false;

	if(!BuildAddressRange(strIn, &range[0])) return false;

	for(i1=range[0]; i1<=range[1]; i1++){
		for(i2=range[2]; i2<=range[3]; i2++){
			for(i3=range[4]; i3<=range[5]; i3++){
				for(i4=range[6]; i4<=range[7]; i4++){
					if(!AddAddress(i1, i2, i3, i4))
						return false;
				}
			}
		}
	}

	return true;
}

//---------------------------------------------------------------------------

bool ListOfAddresses::MayBeIPv6Address(CString strIn)
{
	int pos;

	pos = strIn.Find(":", 0);
	return pos==-1 ? false : true;
}

//---------------------------------------------------------------------------

bool ListOfAddresses::AddAddress6(int w1, int w2, int w3, int w4, int w5, int w6, int w7, int w8)
{
	in_addr6 ia6;

	ia6.u.Word[0] = htons(w1);
	ia6.u.Word[1] = htons(w2);
	ia6.u.Word[2] = htons(w3);
	ia6.u.Word[3] = htons(w4);
	ia6.u.Word[4] = htons(w5);
	ia6.u.Word[5] = htons(w6);
	ia6.u.Word[6] = htons(w7);
	ia6.u.Word[7] = htons(w8);

	return AddAddress6(&ia6);
}

bool ListOfAddresses::AddAddress6(in_addr6* iaIn)
{
	MFullAddress *addr;
	int cnt;

	if(iaIn==NULL) return false;

	addr = CreateAddress();
	if(addr==NULL) return false;

	addr->addrIPv6.Set(iaIn);

	cnt = (int)theVector.size();
	theVector.push_back(addr);
	cnt = (int)theVector.size() - cnt;
	if(cnt!=1){
		delete addr;
		return false;
	}

	return true;
}

bool ListOfAddresses::BuildRange6(CString strIn, int* range)
{
	CString v1, v2;
	int pos;
	int bbb;

	if(range==NULL) return false;

	if(strIn.CompareNoCase("*")==0){
		range[0] = 0x0000;
		range[1] = 0xFFFF;
		return true;
	}

	pos=strIn.Find('-', 0);
	if(pos!=-1){
		v1 = strIn.Left(pos);
		v2 = strIn.Mid(pos+1);
	}
	else{
		v1 = strIn;
		v2 = strIn;
	}

	try{
		range[0] = _tcstoul(v1, NULL, 16);
		range[1] = _tcstoul(v2, NULL, 16);
	}
	catch(...){
		return false;
	}

	if(range[0]<0 || range[0]>0xFFFF) return false;
	if(range[1]<0 || range[1]>0xFFFF) return false;

	if(range[0]>range[1]){
		bbb      = range[0];
		range[0] = range[1];
		range[1] = bbb;
	}

	return true;
}

bool ListOfAddresses::BuildAddressRange6(CString strIn, int* range)
{
	CString str, r1, r2, r3, r4, r5, r6, r7, r8;
	int pos;

	str = strIn;

	pos = str.Find(':', 0);
	if(pos==-1) return false;
	r1  = str.Left(pos);
	str = str.Mid(pos+1);

	pos = str.Find(':', 0);
	if(pos==-1) return false;
	r2  = str.Left(pos);
	str = str.Mid(pos+1);

	pos = str.Find(':', 0);
	if(pos==-1) return false;
	r3  = str.Left(pos);
	str = str.Mid(pos+1);

	pos = str.Find(':', 0);
	if(pos==-1) return false;
	r4  = str.Left(pos);
	str = str.Mid(pos+1);

	pos = str.Find(':', 0);
	if(pos==-1) return false;
	r5  = str.Left(pos);
	str = str.Mid(pos+1);

	pos = str.Find(':', 0);
	if(pos==-1) return false;
	r6  = str.Left(pos);
	str = str.Mid(pos+1);

	pos = str.Find(':', 0);
	if(pos==-1) return false;
	r7  = str.Left(pos);
	r8  = str.Mid(pos+1);

	if(!BuildRange6(r1, &range[0])) return false;
	if(!BuildRange6(r2, &range[2])) return false;
	if(!BuildRange6(r3, &range[4])) return false;
	if(!BuildRange6(r4, &range[6])) return false;
	if(!BuildRange6(r5, &range[8])) return false;
	if(!BuildRange6(r6, &range[10])) return false;
	if(!BuildRange6(r7, &range[12])) return false;
	if(!BuildRange6(r8, &range[14])) return false;

	return true;
}

bool ListOfAddresses::AddAddressFromString6(CString strIn)
{
	int range[16];
	int i1, i2, i3, i4, i5, i6, i7, i8;
	int pos;
	MAddressIPv6 ip6;
	in_addr6 ia6;

	if(strIn.IsEmpty()) return false;

	pos = strIn.Find('-', 0);
	if(pos==-1){
		// is not a range, compressed form allowed
		if(!ip6.SetS(strIn)) return false;
		ip6.Get(&ia6);
		return AddAddress6(&ia6);
	}

	if(!BuildAddressRange6(strIn, &range[0])) return false;

	for(i1=range[0]; i1<=range[1]; i1++){
		for(i2=range[2]; i2<=range[3]; i2++){
			for(i3=range[4]; i3<=range[5]; i3++){
				for(i4=range[6]; i4<=range[7]; i4++){
					for(i5=range[8]; i5<=range[9]; i5++){
						for(i6=range[10]; i6<=range[11]; i6++){
							for(i7=range[12]; i7<=range[13]; i7++){
								for(i8=range[14]; i8<=range[15]; i8++){
									if(!AddAddress6(i1, i2, i3, i4, i5, i6, i7, i8))
										return false;
								}
							}
						}
					}
				}
			}
		}
	}

	return true;
}

//---------------------------------------------------------------------------

bool ListOfAddresses::LoadFromString(CString strIn)
{
	CString str, sToken;
	int pos;

	CleanUp();

	str = strIn.Trim();
	while(!str.IsEmpty()){
		pos = str.Find(',', 0);
		if(pos==-1){
			sToken = str;
			str.Empty();
		}
		else{
			sToken = str.Left(pos);
			sToken = sToken.Trim();

			str = str.Mid(pos+1);
			str = str.Trim();
		}

		if(MayBeIPv6Address(sToken)){
			if(!AddAddressFromString6(sToken))
				return false;
		}
		else{
			if(!AddAddressFromString(sToken))
				return false;
		}
	}

	return true;
}

void ListOfAddresses::Clear(void)
{
	CleanUp();
}

//---------------------------------------------------------------------------

int ListOfAddresses::GetSize(void)
{
	return (int)theVector.size();
}

MFullAddress* ListOfAddresses::GetFirst(void)
{
	if(theVector.size()==0) return 0;

	iter = theVector.begin();
	return *iter;
}

MFullAddress* ListOfAddresses::GetNext(void)
{
	iter++;
	return *iter;
}

MFullAddress* ListOfAddresses::GetByIdx(int idxIn)
{
	if(idxIn<0)          return NULL;
	if(idxIn>=GetSize()) return NULL;

	return theVector[idxIn];
}

int ListOfAddresses::GetSize4(void)
{
	MFullAddress *addr;
	int res;

	res = 0;
	for(iter=theVector.begin(); iter!=theVector.end(); iter++){
		addr = *iter;
		if(addr!=NULL){
			if(!addr->addrIP.IsEmpty())
				res++;
		}
	}

	return res;
}

int ListOfAddresses::GetSize6(void)
{
	MFullAddress *addr;
	int res;

	res = 0;
	for(iter=theVector.begin(); iter!=theVector.end(); iter++){
		addr = *iter;
		if(addr!=NULL){
			if(!addr->addrIPv6.IsEmpty())
				res++;
		}
	}

	return res;
}

//---------------------------------------------------------------------------

bool MFullAddressGreater(MFullAddress* a1, MFullAddress* a2)
{
	if(a2==NULL) return true;
	if(a1==NULL) return false;

	if(a1->addrIP.GetD() != a2->addrIP.GetD())
		return htonl(a1->addrIP.GetD()) < htonl(a2->addrIP.GetD());

	in_addr6 ia1;
	in_addr6 ia2;

	a1->addrIPv6.Get(&ia1);
	a2->addrIPv6.Get(&ia2);

	if(ia1.u.Word[0] < ia2.u.Word[0]) return true;
	if(ia1.u.Word[1] < ia2.u.Word[1]) return true;
	if(ia1.u.Word[2] < ia2.u.Word[2]) return true;
	if(ia1.u.Word[3] < ia2.u.Word[3]) return true;
	if(ia1.u.Word[4] < ia2.u.Word[4]) return true;
	if(ia1.u.Word[5] < ia2.u.Word[5]) return true;
	if(ia1.u.Word[6] < ia2.u.Word[6]) return true;
	if(ia1.u.Word[7] < ia2.u.Word[7]) return true;

	return false;
}

void ListOfAddresses::SortTheList(void)
{
	std::sort(theVector.begin(), theVector.end(), MFullAddressGreater);
}

void ListOfAddresses::RandomizeList(void)
{
	std::random_shuffle(theVector.begin(), theVector.end());
}

//---------------------------------------------------------------------------
